"""
装饰器工具
提供常用的函数装饰器
"""

import functools
import time
import asyncio
from typing import Callable, Any, Optional
from src.utils.logging import get_logger
from src.exceptions import ResearchException

logger = get_logger(__name__)

def handle_errors(default_return: Any = None, log_level: str = "ERROR"):
    """
    错误处理装饰器
    
    Args:
        default_return: 发生错误时返回的默认值
        log_level: 日志级别 (ERROR, WARNING, INFO)
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            try:
                result = await func(*args, **kwargs)
                # 确保返回的是实际结果而不是协程对象
                import inspect
                while inspect.iscoroutine(result) or inspect.isawaitable(result):
                    result = await result
                return result
            except ResearchException as e:
                # 已知的业务异常，记录警告
                getattr(logger, log_level.lower())(
                    f"业务异常 [{func.__name__}]: {e}",
                    extra={"function": func.__name__, "exception_type": type(e).__name__}
                )
                return default_return
            except Exception as e:
                # 未知的系统异常，记录错误
                logger.error(
                    f"系统异常 [{func.__name__}]: {e}",
                    exc_info=True,
                    extra={"function": func.__name__, "exception_type": type(e).__name__}
                )
                return default_return
                
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except ResearchException as e:
                # 已知的业务异常，记录警告
                getattr(logger, log_level.lower())(
                    f"业务异常 [{func.__name__}]: {e}",
                    extra={"function": func.__name__, "exception_type": type(e).__name__}
                )
                return default_return
            except Exception as e:
                # 未知的系统异常，记录错误
                logger.error(
                    f"系统异常 [{func.__name__}]: {e}",
                    exc_info=True,
                    extra={"function": func.__name__, "exception_type": type(e).__name__}
                )
                return default_return
                
        # 根据函数是否为异步函数选择合适的包装器
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    return decorator

def timing(log_level: str = "INFO"):
    """
    函数执行时间记录装饰器
    
    Args:
        log_level: 日志级别
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            start_time = time.time()
            result = await func(*args, **kwargs)
            end_time = time.time()
            
            execution_time = end_time - start_time
            getattr(logger, log_level.lower())(
                f"函数执行时间 [{func.__name__}]: {execution_time:.3f}秒",
                extra={
                    "function": func.__name__,
                    "execution_time": execution_time,
                    "unit": "seconds"
                }
            )
            
            return result
            
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            
            execution_time = end_time - start_time
            getattr(logger, log_level.lower())(
                f"函数执行时间 [{func.__name__}]: {execution_time:.3f}秒",
                extra={
                    "function": func.__name__,
                    "execution_time": execution_time,
                    "unit": "seconds"
                }
            )
            
            return result
            
        # 根据函数是否为异步函数选择合适的包装器
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    return decorator

def retry(max_attempts: int = 3, delay: float = 1.0, 
          exceptions: tuple = (Exception,), log_level: str = "WARNING"):
    """
    重试装饰器
    
    Args:
        max_attempts: 最大重试次数
        delay: 重试延迟（秒）
        exceptions: 需要重试的异常类型
        log_level: 日志级别
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            last_exception = None
            for attempt in range(1, max_attempts + 1):
                try:
                    return await func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    if attempt < max_attempts:
                        getattr(logger, log_level.lower())(
                            f"重试 [{func.__name__}] 第 {attempt}/{max_attempts} 次: {e}",
                            extra={
                                "function": func.__name__,
                                "attempt": attempt,
                                "max_attempts": max_attempts,
                                "exception": str(e)
                            }
                        )
                        await asyncio.sleep(delay)
                    else:
                        getattr(logger, log_level.lower())(
                            f"重试失败 [{func.__name__}] 达到最大次数 {max_attempts}: {e}",
                            extra={
                                "function": func.__name__,
                                "max_attempts": max_attempts,
                                "exception": str(e)
                            }
                        )
                        raise e
            if last_exception:
                raise last_exception  # 这行应该不会执行，但为了类型安全
            else:
                raise RuntimeError("重试失败但未捕获异常")
                
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            last_exception = None
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    if attempt < max_attempts:
                        getattr(logger, log_level.lower())(
                            f"重试 [{func.__name__}] 第 {attempt}/{max_attempts} 次: {e}",
                            extra={
                                "function": func.__name__,
                                "attempt": attempt,
                                "max_attempts": max_attempts,
                                "exception": str(e)
                            }
                        )
                        time.sleep(delay)
                    else:
                        getattr(logger, log_level.lower())(
                            f"重试失败 [{func.__name__}] 达到最大次数 {max_attempts}: {e}",
                            extra={
                                "function": func.__name__,
                                "max_attempts": max_attempts,
                                "exception": str(e)
                            }
                        )
                        raise e
            if last_exception:
                raise last_exception  # 这行应该不会执行，但为了类型安全
            else:
                raise RuntimeError("重试失败但未捕获异常")
                
        # 根据函数是否为异步函数选择合适的包装器
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    return decorator

def validate_args(validation_func: Optional[Callable] = None):
    """
    参数验证装饰器
    
    Args:
        validation_func: 自定义验证函数，接收(args, kwargs)并返回验证结果
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if validation_func:
                validation_result = validation_func(args, kwargs)
                if not validation_result:
                    raise ValueError("参数验证失败")
            
            # 基本的非空检查
            for i, arg in enumerate(args):
                if arg is None:
                    raise ValueError(f"位置参数 {i} 不能为 None")
            
            for key, value in kwargs.items():
                if value is None:
                    raise ValueError(f"关键字参数 {key} 不能为 None")
            
            return func(*args, **kwargs)
        return wrapper
    return decorator

def cache_result(ttl: Optional[float] = None, max_size: Optional[int] = None):
    """
    结果缓存装饰器（简单内存缓存）
    
    Args:
        ttl: 缓存存活时间（秒），None表示不过期
        max_size: 最大缓存条目数，None表示无限制
    """
    cache = {}
    cache_times = {}
    
    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = (args, frozenset(kwargs.items()))
            
            current_time = time.time()
            
            # 检查缓存是否存在且未过期
            if cache_key in cache:
                if ttl is None or (current_time - cache_times[cache_key] < ttl):
                    return cache[cache_key]
                else:
                    # 缓存过期，删除
                    del cache[cache_key]
                    del cache_times[cache_key]
            
            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            cache[cache_key] = result
            cache_times[cache_key] = current_time
            
            # 如果超过最大大小，删除最旧的条目
            if max_size is not None and len(cache) > max_size:
                oldest_key = min(cache_times.items(), key=lambda x: x[1])[0]
                del cache[oldest_key]
                del cache_times[oldest_key]
            
            return result
        return wrapper
    return decorator